﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Odbc;
using UnityCore2.StdLib;

namespace UnityCore2
{
    //Basic objects
    public class UnityToken
    {
        //Data Buffers
        private object[] _token = null;
        
        public UnityToken(string codeln)
        {
            _token = FnRawData.Tokenize(codeln);
        }
        public object[] Value
        {
            get { return _token; }
        }   
    }
    //Contains states
    public class UnityBuffer
    {
        //Internal buffers
        UnityToken[] _tokens = new UnityToken[0];
        DataTable[] _data = new DataTable[0];
        int _curTable = -1;

        //Descriptors
        string _fID = "fID";
        string _fStamp = "fStamp";

        //Table creation
        public void AddTable(string name, string[] fields, Type[] fieldtypes)
        {
            if (fields.Length != fieldtypes.Length) throw new UnityException("AddTable", Err.Code(2), Err.Msg(2));
            //Create and add new table.
            FnRawData.MemPush(ref _data, FnDatabase.CreateTable(name, fields, fieldtypes));
            if (_curTable == -1) _curTable = 0;
        }
        internal void AddTable(OdbcDataReader reader)
        {
            //Create from reader.
            FnRawData.MemPush(ref _data, FnDatabase.GetTable(reader));
            if (_curTable == -1) _curTable = 0;
        }
        internal void AddTable(DataTable datatable)
        {
            //Check if table is not null.
            if (datatable == null) throw new UnityException("AddTable",Err.Code(0), Err.Msg(0));
            //Validate the table descriptor
            int descriptorFound = 0;
            for (int i = 0; i < datatable.Columns.Count; i++)
            {
                if (datatable.Columns[i].ColumnName.Equals(_fID)) descriptorFound++;
                if (datatable.Columns[i].ColumnName.Equals(_fStamp)) descriptorFound++;
            }
            //Check if descriptors are found.
            if (descriptorFound != 2) throw new UnityException("AddTable",Err.Code(1), Err.Msg(1));

            //Add the table to stack.
            FnRawData.MemPush(ref _data, datatable);
            if (_curTable == -1) _curTable = 0;
        }

        //Token Creation
        public void Command(string cmd)
        {
            FnRawData.MemPush(ref _tokens, new UnityToken(cmd));
        }

        //Resource Management
        public void Clear()
        {
            _tokens = new UnityToken[0];
            _data = new DataTable[0];
        }

        //Data Manipulation
        public int SelectedTable
        {
            get { return _curTable; }
            set { _curTable = value; }
        }
        public object GetData(int row, int col)
        {
            object res = _data[_curTable].Rows[row][col];
            return res;
        }
        public object GetData(int row, string colname)
        {
            object res = _data[_curTable].Rows[row][colname];
            return res;
        }
        public object[] GetRowData(int row)
        {
            object[] res = new object[_data[_curTable].Columns.Count - 2];
            int cnt = 0;
            for (int i = 0; i < _data[_curTable].Columns.Count; i++)
            {
                if (_data[_curTable].Columns[i].ColumnName != _fID && _data[_curTable].Columns[i].ColumnName != _fStamp)
                {
                    res[cnt] = _data[_curTable].Rows[row][i];
                    cnt++;
                }
            }
            return res;
        }
        

    }

    public class UnityExecutionUnit
    {

    }

    //Error codes and messages
    internal class Err
    {
        private Err() { }
        static string[] _code = new string[] 
        {
            "00000",
            "00001",
            "00002"
        };
        static string[] _msg = new string[] 
        { 
            "Null table detected.",
            "The table being imported have invalid fields.",
            "The number of fields does not correspond to the number of fieldtypes."
        };

        internal static string Code(int index)
        {
            return _code[index];
        }
        internal static string Msg(int index)
        {
            return _msg[index];
        }
    }
    //Exception class
    public class UnityException : Exception
    {
        string _code = "";
        object _method = null;
        public UnityException(string code, string msg)
            : base(msg)
        {
            _code = code;
        }
        public UnityException(object method, string code, string msg)
            : base(msg)
        {
            _code = code;
            _method = method;
        }
        public string Code
        {
            get { return _code; }
            internal set { _code = value; }
        }
        public object CallingMethod
        {
            get { return _method; }
            internal set { _method = value; }
        }
    }
}